package com.telit.common.config;


import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ToStringSerializer;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.telit.common.filter.GlobalExceptionFilter;
import com.telit.common.filter.HttpInterceptor;
import okhttp3.OkHttpClient;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * Create by Chencf on 2022/9/1
 */
//@Configuration
public class AppConfig {

    /**
     * fastjson转换器
     */
    public static FastJsonHttpMessageConverter getFastJson() {
        //定义一个convert转换消息的对象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

        //添加fastjson的配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();

        // JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
        fastJsonConfig.setSerializerFeatures(
                // SerializerFeature.PrettyFormat,					//输出json格式化
                SerializerFeature.WriteDateUseDateFormat,        //日期类型默认使用默认格式化
                SerializerFeature.DisableCircularReferenceDetect//取消对象的循环引用
                // SerializerFeature.WriteMapNullValue				//值为null的字段，仍然输出
        );
        fastConverter.setFastJsonConfig(fastJsonConfig);

        //解决Long转json精度丢失的问题
        SerializeConfig serializeConfig = SerializeConfig.globalInstance;
        serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
        serializeConfig.put(Long.class, ToStringSerializer.instance);
        serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
        fastJsonConfig.setSerializeConfig(serializeConfig);

        //处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        return fastConverter;
    }

    /**
     * 默认全局异常拦截Filter
     */
    @Bean
    public FilterRegistrationBean globalExceptionFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        GlobalExceptionFilter globalExceptionFilter = new GlobalExceptionFilter();
        registrationBean.setFilter(globalExceptionFilter);
        List<String> urlPatterns = new ArrayList<>();
        urlPatterns.add("/*");
        registrationBean.setUrlPatterns(urlPatterns);
        registrationBean.setOrder(-1);
        return registrationBean;
    }


    /**
     * 配置RedisTemplate  用于Redis连接
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setStringSerializer(new StringRedisSerializer());

        /**
         * 这里我们不使用FastJson的序列化器，因为在我们项目中很多地方都使用FastJson的注解标识非序列化
         * 这会跟Redis存储的期望值不一致
         */
        // redisTemplate.setValueSerializer(new FastJsonRedisSerializer(Object.class));
        redisTemplate.setConnectionFactory(factory);

        return redisTemplate;
    }

//    /**
//     * redis 发布订阅  注册监听者
//     */
//    @Bean
//    RedisMessageListenerContainer redisMessageListener(RedisConnectionFactory connectionFactory){
//        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
//        container.setConnectionFactory(connectionFactory);
//        // 定义监听类 与 监听的Topic 可以一对多
//        container.addMessageListener(new ShardingRedisListener(),new ChannelTopic(RedisListenerTopicConst.AUTO_CREATE_TABLE_UPDATE_TOPIC));
//
//        // 指定一个 并发线程数为10  等待队列无限的线程池
//        ThreadPoolExecutor threadPoolExecutor = ExecutorBuilder.create()
//                .setCorePoolSize(10)
//                .setWorkQueue(new LinkedBlockingQueue())
//                .build();
//        container.setTaskExecutor(threadPoolExecutor);
//        return container;
//    }

    /**
     * 配置RestTemplate   用于远程Http连接
     */
    @Bean
    public RestTemplate OKHttp3RestTemplate() {
        // 底层使用okHttp3
        OkHttpClient client = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .connectTimeout(1, TimeUnit.MINUTES)
                .readTimeout(10, TimeUnit.MINUTES)
                .build();
        OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory(client);

        RestTemplate restTemplate = new RestTemplate(okHttp3ClientHttpRequestFactory);

        // 参数转换器使用fastjson
        List<HttpMessageConverter<?>> httpMessageConverterList = restTemplate.getMessageConverters();
        Iterator<HttpMessageConverter<?>> iterator = httpMessageConverterList.iterator();
        if (iterator.hasNext()) {
            HttpMessageConverter<?> converter = iterator.next();
            //原有的String是ISO-8859-1编码 去掉
            if (converter instanceof StringHttpMessageConverter) {
                iterator.remove();
            }
        }
        httpMessageConverterList.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        httpMessageConverterList.add(0, getFastJson());

        // 添加interceptor，打印请求参数
        restTemplate.getInterceptors().add(new HttpInterceptor());
        return restTemplate;
    }


    /**
     * 允许跨域设置
     */
    // @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 允许的域名白名单，可以*
        corsConfiguration.addAllowedHeader("*"); // 允许任何头
        corsConfiguration.addAllowedMethod(HttpMethod.GET); // 允许哪些类型请求，可以*
        corsConfiguration.addAllowedMethod(HttpMethod.POST);
        corsConfiguration.addAllowedMethod(HttpMethod.PUT);
        corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
        corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
        corsConfiguration.setAllowCredentials(true);//是否允许携带cookie
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/api/**", corsConfiguration); // 哪些path的接口可以被跨域请求
        return new CorsFilter(source);
    }

}
